home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / vmMigrate.c < prev    next >
C/C++ Source or Header  |  1990-11-06  |  20KB  |  747 lines

  1. /*
  2.  * vmMigrate.c --
  3.  *
  4.  *    Routines to handle process migration from the standpoint of virtual
  5.  *    memory.
  6.  *
  7.  * Copyright 1986 Regents of the University of California
  8.  * All rights reserved.
  9.  */
  10.  
  11. #ifndef lint
  12. static char rcsid[] = "$Header: /sprite/src/kernel/vm/RCS/vmMigrate.c,v 9.11 90/11/06 17:16:40 rab Exp $ SPRITE (Berkeley)";
  13. #endif not lint
  14.  
  15. #include <sprite.h>
  16. #include <vm.h>
  17. #include <vmInt.h>
  18. #include <lock.h>
  19. #include <proc.h>
  20. #include <procMigrate.h>
  21. #include <fs.h>
  22. #include <fsio.h>
  23. #include <stdlib.h>
  24. #include <byte.h>
  25. #include <stdio.h>
  26. #include <bstring.h>
  27. #include <assert.h>    
  28.  
  29. static ReturnStatus EncapSegment _ARGS_((Vm_Segment *segPtr,
  30.     Proc_ControlBlock *procPtr, Address *bufPtrPtr));
  31. ENTRY static void PrepareSegment _ARGS_((Vm_Segment *segPtr));
  32. static ReturnStatus FlushSegment _ARGS_((Vm_Segment *segPtr));
  33. static void FreePages _ARGS_((Vm_Segment *segPtr));
  34. ENTRY static void LoadSegment _ARGS_((int length, register Address buffer,
  35.     register Vm_Segment *segPtr));
  36. ENTRY static ReturnStatus CheckSharers _ARGS_((register Vm_Segment *segPtr,
  37.     Proc_EncapInfo *infoPtr));
  38.  
  39. /*
  40.  * Define the number of ints transferred... FIXME: change to a struct.
  41.  */
  42. #define NUM_FIELDS 5
  43.  
  44.  
  45.  
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * Vm_InitiateMigration --
  50.  *
  51.  *    Set up a process for migration.  Lock the dirty pages of each
  52.  *    segment, and free the rest.  Flush the dirty pages to disk.
  53.  *
  54.  * Results:
  55.  *    SUCCESS is returned directly; the size of the encapsulated state
  56.  *    is returned in infoPtr->size.
  57.  *
  58.  * Side effects:
  59.  *    The pages in the process are flushed.  Any copy-on-write pages
  60.  *    are isolated.
  61.  *
  62.  *----------------------------------------------------------------------
  63.  */
  64.  
  65. /* ARGSUSED */
  66. ReturnStatus
  67. Vm_InitiateMigration(procPtr, hostID, infoPtr)
  68.     Proc_ControlBlock *procPtr;            /* process being migrated */
  69.     int hostID;                    /* host to which it migrates */
  70.     Proc_EncapInfo *infoPtr;            /* area w/ information about
  71.                          * encapsulated state */
  72. {
  73.     int            seg;
  74.     Vm_Segment         *segPtr;
  75.     Vm_Segment         **segPtrPtr;
  76.     int            fsSize;
  77.     int            size = 0;
  78.     ReturnStatus    status;
  79.     int            varSize;
  80.  
  81.  
  82.     segPtrPtr = procPtr->vmPtr->segPtrArray;
  83.     status = CheckSharers(segPtrPtr[VM_HEAP], infoPtr);
  84.     if (status != SUCCESS) {
  85.     return(status);
  86.     }
  87.     fsSize = Fs_GetEncapSize();
  88.  
  89.     /*
  90.      * Prepare each segment for migration.  This involves some work in
  91.      * a monitored procedure and an unmonitored one.
  92.      */
  93.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  94.     segPtr = segPtrPtr[seg];
  95.     if (segPtr->type != VM_CODE) {
  96.         if (vm_CanCOW) {
  97.         /*
  98.          * Get rid of all copy-on-write dependencies.
  99.          */
  100.         status = VmCOWCopySeg(segPtr);
  101.         if (status != SUCCESS) {
  102.             printf("Warning: Vm_MigrateSegment: Could not copy segment\n");
  103.             return(status);
  104.         }
  105.         }
  106.         PrepareSegment(segPtr);
  107.         /*
  108.          * Unlock the process while flushing it to the server -- we might
  109.          * have to wait a while while this is going on.
  110.          */
  111.         Proc_Unlock(procPtr);
  112.         status = FlushSegment(segPtr);
  113.         Proc_Lock(procPtr);
  114.         if (status != SUCCESS) {
  115.         return(status);
  116.         }
  117.         varSize = segPtr->ptSize * sizeof(Vm_PTE);
  118.     } else {
  119.         varSize = sizeof(Vm_ExecInfo);
  120.     }
  121.     size += NUM_FIELDS * sizeof(int) + varSize + fsSize;
  122.     }
  123.     infoPtr->size = size;
  124.     return(SUCCESS);
  125. }
  126.  
  127.  
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * Vm_EncapState --
  132.  *
  133.  *    Encapsulate the state of a process's virtual memory.  All the
  134.  *    work in going through its page tables has been done, so
  135.  *    just wait for all its pages to be written to disk, then
  136.  *    package up the state.
  137.  *
  138.  * Results:
  139.  *    If any error occurs with writing the swap files, an error is
  140.  *    indicated; otherwise, SUCCESS is returned.
  141.  *
  142.  * Side effects:
  143.  *    Each of the process's segments is freed.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147. /* ARGSUSED */
  148. ReturnStatus
  149. Vm_EncapState(procPtr, hostID, infoPtr, bufferPtr)
  150.     register Proc_ControlBlock     *procPtr;  /* The process being migrated */
  151.     int hostID;                   /* host to which it migrates */
  152.     Proc_EncapInfo *infoPtr;           /* area w/ information about
  153.                         * encapsulated state */
  154.     Address bufferPtr;               /* Pointer to allocated buffer */
  155. {
  156.     ReturnStatus status;
  157.     Vm_Segment         *segPtr;
  158.     Vm_Segment         **segPtrPtr;
  159.     int            seg;
  160.  
  161.  
  162.     /*
  163.      * Encapsulate the virtual memory, and set up the process so the kernel
  164.      * knows the process has no VM on this machine.
  165.      */
  166.     
  167.     procPtr->genFlags |= PROC_NO_VM;
  168.  
  169.     segPtrPtr = procPtr->vmPtr->segPtrArray;
  170.  
  171.     /*
  172.      * Encapsulate each segment.  If it's not a code segment, it must
  173.      * be freed up.
  174.      */
  175.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  176.     segPtr = segPtrPtr[seg];
  177.     if (segPtr->type != VM_CODE) {
  178.         FreePages(segPtr);
  179.         if (segPtr->flags & VM_SEG_IO_ERROR) {
  180.         return(VM_SWAP_ERROR);
  181.         }
  182.     }
  183.         status = EncapSegment(segPtr, procPtr, &bufferPtr);
  184.     if (status != SUCCESS) {
  185.         return(status);
  186.     }
  187.     }
  188.     return(SUCCESS);
  189. }
  190.  
  191.  
  192. /*
  193.  *----------------------------------------------------------------------
  194.  *
  195.  * Vm_DeencapState --
  196.  *
  197.  *    Deencapsulate the state of a process's virtual memory. 
  198.  *    For each segment, get the information from a foreign
  199.  *    Vm_Segment from a buffer and create a segment for it on this
  200.  *    (the remote) node.  Set up the file pointer for its swap file,
  201.  *    if it is a stack or heap segment.  If it is a code segment, do
  202.  *    a Vm_SegmentFind (just as Proc_Exec does) and initialize the
  203.  *    page tables if necessary, then return.
  204.  *
  205.  * Results:
  206.  *    If any error occurs with deencapsulating the swap files, an error is
  207.  *    indicated; otherwise, SUCCESS is returned.
  208.  *
  209.  * Side effects:
  210.  *    Creates segments for the process.
  211.  *
  212.  *----------------------------------------------------------------------
  213.  */
  214. /* ARGSUSED */
  215. ReturnStatus
  216. Vm_DeencapState(procPtr, infoPtr, buffer)
  217.     register Proc_ControlBlock     *procPtr;  /* The process being migrated */
  218.     Proc_EncapInfo *infoPtr;           /* area w/ information about
  219.                         * encapsulated state */
  220.     Address buffer;               /* Pointer to allocated buffer */
  221. {
  222.     ReturnStatus status;
  223.     Vm_Segment         *segPtr;
  224.     int            seg;
  225.     int     offset;
  226.     int     fileAddr;
  227.     int     type;
  228.     int     numPages;
  229.     int     varSize;
  230.     int     ptSize;
  231.     Fs_Stream     *filePtr;
  232.     int     fsInfoSize;
  233.     Vm_ExecInfo    *execInfoPtr;
  234.     Vm_ExecInfo    *oldExecInfoPtr;
  235.     Boolean    usedFile;
  236.  
  237.  
  238.     fsInfoSize = Fs_GetEncapSize();
  239.  
  240.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  241.     Byte_EmptyBuffer(buffer, int, offset);
  242.     Byte_EmptyBuffer(buffer, int, fileAddr);
  243.     Byte_EmptyBuffer(buffer, int, type);
  244.     if (type != seg) {
  245.         if (proc_MigDebugLevel > 0) {
  246.         panic("Vm_DeencapState: mismatch getting segment %d\n",
  247.               seg);
  248.         return(FAILURE);
  249.         }
  250.     }
  251.     Byte_EmptyBuffer(buffer, int, numPages);
  252.     Byte_EmptyBuffer(buffer, int, ptSize);
  253.     switch (type) {
  254.         case VM_CODE: {
  255.         varSize = sizeof(Vm_ExecInfo);
  256.         oldExecInfoPtr = (Vm_ExecInfo *) buffer;
  257.         buffer += varSize;
  258.         status = Fsio_DeencapStream(buffer, &filePtr);
  259.         buffer += fsInfoSize;
  260.         if (status != SUCCESS) {
  261.             printf("Vm_DeencapState: Fsio_DeencapStream returned status %x.\n",
  262.                status);
  263.             return(status);
  264.         }
  265.         assert(filePtr->ioHandlePtr != (Fs_HandleHeader *) NIL);
  266.         segPtr = Vm_FindCode(filePtr, procPtr, &execInfoPtr, &usedFile);
  267.         if (segPtr == (Vm_Segment *) NIL) {
  268.             segPtr = Vm_SegmentNew(VM_CODE, filePtr, fileAddr,
  269.                        numPages, offset, procPtr);
  270.             if (segPtr == (Vm_Segment *) NIL) {
  271.             Vm_InitCode(filePtr, (Vm_Segment *) NIL,
  272.                     (Vm_ExecInfo *) NIL);
  273.             (void)Fs_Close(filePtr);
  274.             return(VM_NO_SEGMENTS);
  275.             }
  276.             Vm_ValidatePages(segPtr, offset, 
  277.                      offset + numPages - 1, FALSE, TRUE);
  278.             Vm_InitCode(filePtr, segPtr, oldExecInfoPtr);
  279.         } else {
  280.             if (!usedFile) {
  281.             (void)Fs_Close(filePtr);
  282.             }
  283.         }
  284.         procPtr->vmPtr->segPtrArray[type] = segPtr;
  285.         break;
  286.         }
  287.         case VM_HEAP: {
  288.         Fsio_StreamCopy(procPtr->vmPtr->segPtrArray[VM_CODE]->filePtr,
  289.                     &filePtr);
  290.         if (filePtr == (Fs_Stream *) NIL) {
  291.             panic("Vm_DeencapState: no code file pointer.\n");
  292.         }
  293.         break;
  294.         }
  295.         case VM_STACK: {
  296.         filePtr = (Fs_Stream *) NIL;
  297.         break;
  298.         }
  299.         default: {
  300.         panic("Vm_DeencapState: unknown segment type.\n");
  301.         }
  302.     }
  303.     if (type != VM_CODE) {
  304.         segPtr = Vm_SegmentNew(type, filePtr, fileAddr, numPages,
  305.                    offset, procPtr);
  306.         if (segPtr == (Vm_Segment *) NIL) {
  307.         return(VM_NO_SEGMENTS);
  308.         }
  309.         procPtr->vmPtr->segPtrArray[type] = segPtr;
  310.         segPtr->ptSize = ptSize;
  311.         varSize = ptSize * sizeof(Vm_PTE);
  312.         LoadSegment(varSize, buffer, segPtr);
  313.         buffer += varSize;
  314.         if (proc_MigDebugLevel > 4) {
  315.         printf("Deencapsulating swap file for segment %d.\n", type);
  316.         }
  317.         status = Fsio_DeencapStream(buffer, &segPtr->swapFilePtr);
  318.         buffer += fsInfoSize;
  319.         if (status != SUCCESS) {
  320.         printf("Vm_DeencapState: Fsio_DeencapStream on swapFile returned status %x.\n",
  321.                status);
  322.         return(status);
  323.         }
  324.         if (proc_MigDebugLevel > 4) {
  325.         printf("Deencapsulated swap file successfully.\n");
  326.         }
  327.         if (segPtr->swapFileName != (char *) NIL) { 
  328.         free(segPtr->swapFileName);
  329.         segPtr->swapFileName = (char *) NIL;
  330.         }
  331.         segPtr->flags |= VM_SWAP_FILE_OPENED;
  332.     }
  333.     }
  334.     return(SUCCESS);
  335. }
  336.  
  337.  
  338. /*
  339.  *----------------------------------------------------------------------
  340.  *
  341.  * Vm_FinishMigration --
  342.  *
  343.  *    Clean up the state of a process's virtual memory after migration.
  344.  *    The process control blocked is assumed to be unlocked on entry.
  345.  *
  346.  *        .. OBSOLETE ..
  347.  *
  348.  * Results:
  349.  *    SUCCESS.
  350.  *
  351.  * Side effects:
  352.  *    Deletes segments for the process.
  353.  *
  354.  *----------------------------------------------------------------------
  355.  */
  356. /* ARGSUSED */
  357. ReturnStatus
  358. Vm_FinishMigration(procPtr, hostID, infoPtr, bufferPtr, failure)
  359.     register Proc_ControlBlock     *procPtr;  /* The process being migrated */
  360.     int hostID;                   /* host to which it migrates */
  361.     Proc_EncapInfo *infoPtr;           /* area w/ information about
  362.                         * encapsulated state */
  363.     Address bufferPtr;               /* Pointer to allocated buffer */
  364.     int failure;               /* indicates whether migration
  365.                           succeeded */
  366. {
  367.     int seg;
  368.     
  369.     if (proc_MigDebugLevel > 4) {
  370.     printf("Vm_FinishMigration called.\n");
  371.     }
  372.     
  373.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  374.     if (proc_MigDebugLevel > 5) {
  375.         printf("Vm_FinishMigration deleting segment %d.\n", seg);
  376.     }
  377.     Vm_SegmentDelete(procPtr->vmPtr->segPtrArray[seg], procPtr);
  378.     }
  379.     /*
  380.      * Would also need to set PROC_NO_VM here...
  381.      */
  382.     return(SUCCESS);
  383. }
  384.  
  385.  
  386. /*
  387.  * ----------------------------------------------------------------------------
  388.  *
  389.  * EncapSegment --
  390.  *
  391.  *     Copy the information from a Vm_Segment into a buffer, ready to
  392.  *    be transferred to another node.  We have to duplicate the
  393.  *    stream to the swap or code file for the segment because
  394.  *    Fsio_EncapStream effectively closes the stream.  By dup'ing the
  395.  *    stream we can later call Vm_SegmentDelete which will close the
  396.  *    stream (again).
  397.  *
  398.  * Results:
  399.  *      If an error occurred writing the swap file, VM_SWAP_ERROR is
  400.  *    returned, else SUCCESS.  The new pointer into the buffer
  401.  *    is returned in *bufPtrPtr.
  402.  *
  403.  * Side effects:
  404.  *      None.
  405.  *
  406.  * ----------------------------------------------------------------------------
  407.  */
  408.  
  409. static ReturnStatus
  410. EncapSegment(segPtr, procPtr, bufPtrPtr)
  411.     Vm_Segment    *segPtr;    /* Pointer to the segment to be migrated */
  412.     Proc_ControlBlock     *procPtr;  /* The process being migrated */
  413.     Address    *bufPtrPtr;    /* pointer to pointer into buffer */
  414. {
  415.     register Address ptr;
  416.     int varSize;
  417.     ReturnStatus status;
  418.     Fs_Stream *dummyStreamPtr;
  419.  
  420.     if (segPtr->type != VM_CODE) {
  421.     varSize = segPtr->ptSize * sizeof(Vm_PTE);
  422.     } else {
  423.     varSize = sizeof(Vm_ExecInfo);
  424.     }
  425.  
  426.     ptr = *bufPtrPtr;
  427.     bcopy((Address) &segPtr->offset, ptr, NUM_FIELDS * sizeof(int));
  428.     ptr += NUM_FIELDS * sizeof(int);
  429.     if (segPtr->type != VM_CODE) {
  430.     bcopy((Address) segPtr->ptPtr, ptr, varSize);
  431.     ptr += varSize;
  432.     Fsio_StreamCopy(segPtr->swapFilePtr, &dummyStreamPtr);
  433.     status = Fsio_EncapStream(segPtr->swapFilePtr, ptr);
  434.     } else {
  435.     bcopy((Address) &segPtr->execInfo, ptr, varSize);
  436.     ptr += varSize;
  437.     Fsio_StreamCopy(segPtr->filePtr, &dummyStreamPtr);
  438.     status = Fsio_EncapStream(segPtr->filePtr, ptr);
  439.     }
  440.     if (status != SUCCESS) {
  441.     return(status);
  442.     }
  443.     *bufPtrPtr = ptr + Fs_GetEncapSize();
  444.  
  445.     if (proc_MigDebugLevel > 4) {
  446.     printf("Deleting segment %d from encapsulation routine.\n",
  447.            segPtr->type);
  448.     }
  449.     Proc_Unlock(procPtr);
  450.     VmMach_HandleSegMigration(segPtr);
  451.     Vm_SegmentDelete(segPtr, procPtr);
  452.     Proc_Lock(procPtr);
  453.     if (proc_MigDebugLevel > 4) {
  454.     printf("Deleted segment.\n");
  455.     }
  456.  
  457.     return(SUCCESS);
  458. }
  459.  
  460.  
  461.  
  462. /*
  463.  *----------------------------------------------------------------------
  464.  *
  465.  * LoadSegment --
  466.  *
  467.  *    Copy the page table for a segment from a buffer area into the
  468.  *     segment's page table.  
  469.  *
  470.  * Results:
  471.  *    None.
  472.  *
  473.  * Side effects:
  474.  *    The page table is loaded.
  475.  *
  476.  *----------------------------------------------------------------------
  477.  */
  478. ENTRY static void
  479. LoadSegment(length, buffer, segPtr)
  480.     int                length;
  481.     register    Address        buffer;
  482.     register    Vm_Segment    *segPtr;
  483. {
  484.     LOCK_MONITOR;
  485.  
  486.     bcopy(buffer, (Address) segPtr->ptPtr, length);
  487.  
  488.     UNLOCK_MONITOR;
  489. }
  490.  
  491.  
  492. /*
  493.  *----------------------------------------------------------------------
  494.  *
  495.  * CheckSharers --
  496.  *
  497.  *    Verify that a process is not using shared memory.  
  498.  *
  499.  * Results:
  500.  *    SUCCESS if not, or GEN_PERMISSION_DENIED if so.
  501.  *    Once we can handle shared memory processes, it will return
  502.  *    SUCCESS and rely on the special flag in the encapInfo structure
  503.  *    to fix things up.
  504.  *
  505.  * Side effects:
  506.  *    None.
  507.  *
  508.  *----------------------------------------------------------------------
  509.  */
  510. ENTRY static ReturnStatus
  511. CheckSharers(segPtr, infoPtr)
  512.     register    Vm_Segment    *segPtr;
  513.     Proc_EncapInfo *infoPtr;            /* area w/ information about
  514.                          * encapsulated state */
  515.     
  516. {
  517.     LOCK_MONITOR;
  518.  
  519.     if (segPtr->refCount > 1) {
  520.     infoPtr->special = 1;
  521.     if (proc_MigDebugLevel > 0) {
  522.         printf("Vm_InitiateMigration: can't migrate process sharing heap.\n");
  523.     }
  524.     UNLOCK_MONITOR;
  525.     return(FAILURE);
  526.     }
  527.     UNLOCK_MONITOR;
  528.     return(SUCCESS);
  529. }
  530.  
  531.  
  532. /*
  533.  * ----------------------------------------------------------------------------
  534.  *
  535.  * PrepareSegment --
  536.  *
  537.  *    Set up a segment to be migrated.  Lock its dirty pages and free
  538.  *    the rest.  
  539.  *
  540.  * Results:
  541.  *         The number of pages flushed is returned.
  542.  *
  543.  * Side effects:
  544.  *         All modified pages allocated to the segment are locked; other
  545.  *    pages are freed.
  546.  *
  547.  * ----------------------------------------------------------------------------
  548.  */
  549. ENTRY static void
  550. PrepareSegment(segPtr)
  551.     Vm_Segment    *segPtr;    /* Pointer to the segment to be flushed */
  552. {
  553.     Vm_PTE        *ptePtr;
  554.     Vm_VirtAddr        virtAddr;
  555.     Boolean        referenced;
  556.     Boolean        modified;
  557.     register int    i;
  558.  
  559.     LOCK_MONITOR;
  560.  
  561.     virtAddr.segPtr = segPtr;
  562.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  563.  
  564.     if (segPtr->type == VM_STACK) {
  565.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  566.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  567.     } else {
  568.     virtAddr.page = segPtr->offset;
  569.     ptePtr = segPtr->ptPtr;
  570.     }
  571.  
  572.     /*
  573.      * Free all clean pages that this segment has in real memory.
  574.      * Lock the dirty ones.
  575.      */
  576.  
  577.     for (i = 0; 
  578.      i < segPtr->numPages; 
  579.      i++, virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  580.     /*
  581.      * If the page is not resident in memory then go to the next page.
  582.      */
  583.     if (!(*ptePtr & VM_PHYS_RES_BIT)) {
  584.         continue;
  585.     }
  586.     /*
  587.      * The page is resident so lock it if it needs to be written, or else
  588.      * free the page frame.
  589.      */
  590.     VmMach_GetRefModBits(&virtAddr, Vm_GetPageFrame(*ptePtr), &referenced,
  591.                  &modified);
  592.     if ((*ptePtr & VM_MODIFIED_BIT) || modified) {
  593.         VmLockPageInt(Vm_GetPageFrame(*ptePtr));
  594.     } else {
  595.         VmPageFreeInt(Vm_GetPageFrame(*ptePtr));
  596.         *ptePtr &= ~(VM_PHYS_RES_BIT | VM_PAGE_FRAME_FIELD);
  597.         segPtr->resPages--;
  598.     }
  599.     }
  600.  
  601.     UNLOCK_MONITOR;
  602. }
  603.  
  604. /*
  605.  * ----------------------------------------------------------------------------
  606.  *
  607.  * FlushSegment --
  608.  *
  609.  *         Flush the dirty pages of a segment to disk.  This part is done
  610.  *    without the monitor lock because it calls monitored procedures.
  611.  *
  612.  * Results:
  613.  *         If the swap file cannot be opened, the error is propagated.  Otherwise,
  614.  *    SUCCESS is returned.
  615.  *
  616.  * Side effects:
  617.  *     All modified pages allocated to the segment are forced to disk.
  618.  *
  619.  * ----------------------------------------------------------------------------
  620.  */
  621. static ReturnStatus
  622. FlushSegment(segPtr)
  623.     Vm_Segment     *segPtr;    /* Pointer to the segment to be flushed */
  624. {
  625.     Vm_PTE        *ptePtr;
  626.     Vm_VirtAddr        virtAddr;
  627.     int            i;
  628.     ReturnStatus    status;
  629. #ifndef CLEAN
  630.     int            pagesWritten = 0;
  631. #endif /* CLEAN */
  632.  
  633.     /*
  634.      * Open the swap file unconditionally.
  635.      */
  636.     
  637.     VmSwapFileLock(segPtr);
  638.     if (!(segPtr->flags & VM_SWAP_FILE_OPENED)) {
  639.     status = VmOpenSwapFile(segPtr);
  640.     if (status != SUCCESS) {
  641.         VmSwapFileUnlock(segPtr);
  642.         return(status);
  643.     }
  644.     }
  645.     VmSwapFileUnlock(segPtr);
  646.  
  647.     virtAddr.segPtr = segPtr;
  648.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  649.  
  650.     if (segPtr->type == VM_STACK) {
  651.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  652.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  653.     } else {
  654.     virtAddr.page = segPtr->offset;
  655.     ptePtr = segPtr->ptPtr;
  656.     }
  657.  
  658.     /*
  659.      * Go through the page table and cause all modified pages to be
  660.      * written to disk.  During encapsulation time, we'll start at the
  661.      * top and free each page.  This has the side-effect of waiting
  662.      * for dirty pages to go to disk.  Note that by doing this
  663.      * two-pass write, multiple pages may be written to disk at once
  664.      * since the writes are asynchronous.
  665.      */
  666.     
  667.     for (i = 0; 
  668.      i < segPtr->numPages; 
  669.      i++, virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  670.     /*
  671.      * If the page is not resident in memory then go to the next page.
  672.      */
  673.     if (!(*ptePtr & VM_PHYS_RES_BIT)) {
  674.         continue;
  675.     }
  676.     /*
  677.      * The page is dirty so put it on the dirty list.  Wait later on
  678.      * for it to be written out.
  679.      */
  680. #ifndef CLEAN
  681.     pagesWritten++;
  682. #endif /* CLEAN */
  683.     
  684.     VmPutOnDirtyList(Vm_GetPageFrame(*ptePtr));
  685.     }
  686. #ifndef CLEAN
  687.     if (proc_MigDoStats) {
  688.         Proc_MigAddToCounter(pagesWritten,
  689.                  &proc_MigStats.varStats.pagesWritten,
  690.                  &proc_MigStats.squared.pagesWritten);
  691.     }
  692. #endif /* CLEAN */
  693.     return(SUCCESS);
  694. }
  695.  
  696.  
  697.  
  698. /*
  699.  *----------------------------------------------------------------------
  700.  *
  701.  * FreePages --
  702.  *
  703.  *    Free the pages of a segment (waiting for them to be written first).
  704.  *
  705.  * Results:
  706.  *    None.
  707.  *
  708.  * Side effects:
  709.  *    The pages are freed..
  710.  *
  711.  *----------------------------------------------------------------------
  712.  */
  713.  
  714. static void
  715. FreePages(segPtr)
  716.     Vm_Segment *segPtr;        /* segment whose pages should be freed */
  717. {
  718.     Vm_PTE        *ptePtr;
  719.     Vm_VirtAddr        virtAddr;
  720.     int            i;
  721.  
  722.     virtAddr.segPtr = segPtr;
  723.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  724.  
  725.     if (segPtr->type == VM_STACK) {
  726.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  727.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  728.     } else {
  729.     virtAddr.page = segPtr->offset;
  730.     ptePtr = segPtr->ptPtr;
  731.     }
  732.  
  733.     for (i = 0; 
  734.      i < segPtr->numPages; 
  735.      i++, virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  736.     /*
  737.      * If the page is not resident in memory then go to the next page.
  738.      */
  739.     if (!(*ptePtr & VM_PHYS_RES_BIT)) {
  740.         continue;
  741.     }
  742.     VmPageFree(Vm_GetPageFrame(*ptePtr));
  743.     segPtr->resPages--;
  744.     *ptePtr = VM_VIRT_RES_BIT | VM_ON_SWAP_BIT;
  745.     }
  746. }
  747.